#include "Base64.h"
#include <stdio.h>

//en la tabla agrego el caracter '=' 
TBase64 Base64 []=
{
	{0,  'A'}, {1,  'B'}, {2,  'C'}, {3,  'D'}, {4,  'E'}, {5,  'F'}, {6,  'G'}, {7,  'H'}, {8,  'I'}, {9,  'J'},
	{10, 'K'}, {11, 'L'}, {12, 'M'}, {13, 'N'}, {14, 'O'}, {15, 'P'}, {16, 'Q'}, {17, 'R'}, {18, 'S'}, {19, 'T'},
	{20, 'U'}, {21, 'V'}, {22, 'W'}, {23, 'X'}, {24, 'Y'}, {25, 'Z'}, {26, 'a'}, {27, 'b'}, {28, 'c'}, {29, 'd'},
	{30, 'e'}, {31, 'f'}, {32, 'g'}, {33, 'h'}, {34, 'i'}, {35, 'j'}, {36, 'k'}, {37, 'l'}, {38, 'm'}, {39, 'n'},
    	{40, 'o'}, {41, 'p'}, {42, 'q'}, {43, 'r'}, {44, 's'}, {45, 't'}, {46, 'u'}, {47, 'v'}, {48, 'w'}, {49, 'x'},
    	{50, 'y'}, {51, 'z'}, {52, '0'}, {53, '1'}, {54, '2'}, {55, '3'}, {56, '4'}, {57, '5'}, {58, '6'}, {59, '7'},
    	{60, '8'}, {61, '9'}, {62, '+'}, {63, '/'}, {64, '='}
};


/**********************************
*Declaraciones			  *				
*-------------			  *		 	
***********************************/
int
base64_get_value(char ascii);

int
b64_ascii_1(char c);

int
b64_ascii_2(char c1, char c2);

int
b64_ascii_3(char c1, char c2);

int
b64_ascii_4(char c);

int
b64_ascii_3_filled(char c);

int
b64_ascii_2_filled(char c);
/*************************************************/


int
b64_encode(char* Buffer, char* binary_data,int LenG )
{
	 int i = 0;
	 int errno = 0;
	for(i = 0; i < B64_MAX_ASCII + 1; i++)
		Buffer[i] = '\0';
	
	switch(LenG)
	{
		case 1: Buffer[0] = b64_ascii_1(binary_data[0]);
			Buffer[1] = b64_ascii_2_filled(binary_data[0]);
			Buffer[2] = Base64[B64_PADDING].ASCII;
			Buffer[3] = Base64[B64_PADDING].ASCII;
			break;
		case 2: Buffer[0] = b64_ascii_1(binary_data[0]);
			Buffer[1] = b64_ascii_2(binary_data[0], binary_data[1]);
			Buffer[2] = b64_ascii_3_filled(binary_data[1]);
			Buffer[3] = Base64[B64_PADDING].ASCII;
			break;
		case 3: Buffer[0] = b64_ascii_1(binary_data[0]);
			Buffer[1] = b64_ascii_2(binary_data[0], binary_data[1]);
			Buffer[2] = b64_ascii_3(binary_data[1], binary_data[2]);
			Buffer[3] = b64_ascii_4(binary_data[2]);
			break;
		default: errno = B64_LENGTH_INVAL;
			break;
	}
	return errno;
}

int
b64_decode(char* Buffer, char* encode_data,int LenG, int* size_Buffer)
{
         int i = 0;
         int errno = 0;
        char byte1, byte2, byte3, byte4, aux;
		
		*size_Buffer = 0;
        if(B64_MAX_ASCII == LenG ){
			
				*size_Buffer = 3;
                for(i = 0; i < B64_MAX_ASCII + 1; i++)
                        Buffer[i] = '\0';

                if((byte1 = (char)base64_get_value(encode_data[0])) == B64_CHARACTER_INVAL )
                        return B64_CHARACTER_INVAL;
                if((byte2 = (char)base64_get_value(encode_data[1])) == B64_CHARACTER_INVAL )
                        return B64_CHARACTER_INVAL;
                if((byte3 = (char)base64_get_value(encode_data[2])) == B64_CHARACTER_INVAL )
                        return B64_CHARACTER_INVAL;
                if((byte4 = (char)base64_get_value(encode_data[3])) == B64_CHARACTER_INVAL )
                        return B64_CHARACTER_INVAL;


                byte1 = byte1 << 2;
                byte1 = byte1 & B64_MASK_SET_2_BW;
                aux = byte2 >> 4;
                aux = aux & B64_MASK_SET_6_UP;
                Buffer[0] = byte1 | aux;

                if(byte3 != 64){
                        byte2 = byte2 << 4;
                        byte2 = byte2 & B64_MASK_SET_4_BW;
                        aux = byte3 >> 2;
                        aux = aux & B64_MASK_SET_4_UP;
                        Buffer[1] = byte2 | aux;
                        if(byte4 != 64){
                                byte3 = byte3 << 6;
                                byte3 = byte3 & B64_MASK_SET_6_BW;
                                aux = byte4 & B64_MASK_SET_2_UP;
                                Buffer[2] = byte3 | aux;
                        }
                        else{
                                Buffer[2] = '\0';
								*size_Buffer = 2;
                        }

                }
                else{
                        Buffer[1] = '\0';
                        Buffer[2] = '\0';
						*size_Buffer = 1;
                }
        }
        else
                errno = B64_LENGTH_INVAL;
        return errno;
}

int
base64_get_value(char ascii)
{
	int i = 0;
	for(i = 0; i < B64_LENGTH_TBASE64; i++)
		if(Base64[i].ASCII == ascii)
			return Base64[i].value;
	return B64_CHARACTER_INVAL;
}



int
b64_ascii_1(char c)
{
	char Nro;
	Nro = c >> 2;
	Nro = Nro & B64_MASK_SET_2_UP;	//Obtengo el pirmer numero
	return Base64[(int)Nro].ASCII;	//Obtengo el ASCII asociado al Nro1
}

int
b64_ascii_2(char c1, char c2)
{
	char Nro, aux;
	Nro = c1 & B64_MASK_SET_6_UP;
	Nro = Nro << 4;
	Nro = Nro & B64_MASK_SET_4_BW;
	aux = c2 >> 4;
	aux = aux & B64_MASK_SET_4_UP;
	Nro = Nro | aux;		//Obtengo el segundo numero
	return Base64[(int)Nro].ASCII;	//Obtengo el ASCII asociado al Nro2
}

int
b64_ascii_3(char c1, char c2)
{
	char Nro, aux;
	Nro = c1 & B64_MASK_SET_4_UP;
	Nro = Nro << 2;
	Nro = Nro & B64_MASK_SET_2_BW;
	aux = c2 >> 6;
	aux = aux & B64_MASK_SET_6_UP;
	Nro = Nro | aux;		//Obtengo el tercer numero
	return Base64[(int)Nro].ASCII;	//Obtengo el ASCII asociado al Nro3
}

int
b64_ascii_4(char c)
{
	char Nro;
	Nro = c & B64_MASK_SET_2_UP;	//Obtengo el tercer numero
	return Base64[(int)Nro].ASCII;	//Obtengo el ASCII asociado al Nro4
}

int
b64_ascii_3_filled(char c)
{
	char Nro;
	Nro = c << 2;
	Nro = Nro & B64_MASK_SET_2_UP;	
	Nro = Nro & B64_MASK_SET_2_BW;	//Obtengo el tercer numero
	return Base64[(int)Nro].ASCII;	//Obtengo el ASCII asociado al Nro3 con relleno
}

int
b64_ascii_2_filled(char c)
{
	char Nro;
	Nro = c << 4;
	Nro = Nro & B64_MASK_SET_2_UP;
	Nro = Nro & B64_MASK_SET_4_BW;	//Obtengo el tercer numero
	return Base64[(int)Nro].ASCII;	//Obtengo el ASCII asociado al Nro2 con relleno
}

